#include "pipeline.h"

#include <gtest/gtest.h>

#include <sstream>
#include <string>
#include <vector>

using namespace cfg;

// 作用：执行 stdout sink，并捕获其向 std::cout 的输出。
// 参数：
//  - root: 传入的只读根对象（可为 nullptr）。
//  - options: 插件选项。
// 返回：pair<成功标志, 捕获到的标准输出文本>，错误将写入 out_errors。
static std::pair<bool, std::string>
write_sink_and_capture(const std::shared_ptr<const Object> & root,
                       const PluginOptions & options,
                       std::vector<ConfigError> & out_errors)
{
    std::ostringstream oss;
    std::streambuf * old = std::cout.rdbuf(oss.rdbuf());
    auto restore = [&]() { std::cout.rdbuf(old); };

    auto sink = PluginRegistry::instance().create_sink("stdout");
    bool ok = sink ? sink->write(root, options, out_errors) : false;
    std::string captured = oss.str();
    restore();
    return {ok, captured};
}

// 作用：构造简单对象用于输出测试：{"b":2, "a":"x", "arr":[1,true,null]}
static std::shared_ptr<const Object>
make_simple_root()
{
    auto arr = std::make_shared<Array>();
    arr->items.push_back(int64_t{1});
    arr->items.push_back(true);
    arr->items.push_back(nullptr);

    auto root = std::make_shared<Object>();
    root->props["b"] = int64_t{2};
    root->props["a"] = std::string("x");
    root->props["arr"] = std::shared_ptr<const Array>(arr);
    return std::shared_ptr<const Object>(root);
}

// 紧凑 JSON 输出，校验键排序与换行行为（默认 newline=true）。
TEST(SinkStdoutTest, CompactDefault)
{
    std::vector<ConfigError> errors;
    PluginOptions opts; // 使用默认格式 json、pretty=false、indent=2、newline=true
    auto [ok, out] = write_sink_and_capture(make_simple_root(), opts, errors);
    ASSERT_TRUE(ok);
    ASSERT_TRUE(errors.empty());
    // 键按字典序排序：a, arr, b
    EXPECT_EQ(out, std::string("{\"a\":\"x\",\"arr\":[1,true,null],\"b\":2}\n"));
}

// 美化输出，指定缩进为 4。
TEST(SinkStdoutTest, PrettyIndent4)
{
    std::vector<ConfigError> errors;
    PluginOptions opts{{"pretty", "true"}, {"indent", "4"}};
    auto [ok, out] = write_sink_and_capture(make_simple_root(), opts, errors);
    ASSERT_TRUE(ok);
    ASSERT_TRUE(errors.empty());
    std::string expected;
    expected += "{\n";
    expected += "    \"a\": \"x\",\n";
    expected += "    \"arr\": [\n";
    expected += "        1,\n";
    expected += "        true,\n";
    expected += "        null\n";
    expected += "    ],\n";
    expected += "    \"b\": 2\n";
    expected += "}\n";
    EXPECT_EQ(out, expected);
}

// 关闭末尾换行（newline=false）。
TEST(SinkStdoutTest, NoTrailingNewline)
{
    std::vector<ConfigError> errors;
    PluginOptions opts{{"newline", "false"}};
    auto [ok, out] = write_sink_and_capture(make_simple_root(), opts, errors);
    ASSERT_TRUE(ok);
    ASSERT_TRUE(errors.empty());
    EXPECT_EQ(out, std::string("{\"a\":\"x\",\"arr\":[1,true,null],\"b\":2"));
}

// 缩进为负数时回退到默认 2，与 pretty=true 结合验证。
TEST(SinkStdoutTest, NegativeIndentFallback)
{
    std::vector<ConfigError> errors;
    PluginOptions opts{{"pretty", "true"}, {"indent", "-1"}};
    auto [ok, out] = write_sink_and_capture(make_simple_root(), opts, errors);
    ASSERT_TRUE(ok);
    ASSERT_TRUE(errors.empty());
    std::string expected;
    expected += "{\n";
    expected += "  \"a\": \"x\",\n";
    expected += "  \"arr\": [\n";
    expected += "    1,\n";
    expected += "    true,\n";
    expected += "    null\n";
    expected += "  ],\n";
    expected += "  \"b\": 2\n";
    expected += "}\n";
    EXPECT_EQ(out, expected);
}

// 根为空时输出 "null"。
TEST(SinkStdoutTest, NullRoot)
{
    std::vector<ConfigError> errors;
    PluginOptions opts; // 默认 newline=true
    std::shared_ptr<const Object> null_root;
    auto [ok, out] = write_sink_and_capture(null_root, opts, errors);
    ASSERT_TRUE(ok);
    ASSERT_TRUE(errors.empty());
    EXPECT_EQ(out, std::string("null\n"));
}

// 字符串转义覆盖：引号、反斜杠与控制字符（\t, \n, \r）。
TEST(SinkStdoutTest, StringEscapes)
{
    auto root = std::make_shared<Object>();
    root->props["s"] = std::string("a\"b\\c\t\n\r");
    std::vector<ConfigError> errors;
    PluginOptions opts; // 紧凑输出
    auto [ok, out] = write_sink_and_capture(std::shared_ptr<const Object>(root), opts, errors);
    ASSERT_TRUE(ok);
    ASSERT_TRUE(errors.empty());
    EXPECT_EQ(out, std::string("{\"s\":\"a\\\"b\\\\c\\t\\n\\r\"}\n"));
}

// 非法 format 选项触发校验错误并返回 false。
TEST(SinkStdoutTest, InvalidFormatOption)
{
    std::vector<ConfigError> errors;
    PluginOptions opts{{"format", "yaml"}};
    auto [ok, out] = write_sink_and_capture(make_simple_root(), opts, errors);
    ASSERT_FALSE(ok);
    ASSERT_TRUE(out.empty());
    bool found = false;
    for (const auto & e : errors)
        if (e.message.find("invalid value for option 'format'") != std::string::npos)
        {
            found = true;
            break;
        }
    EXPECT_TRUE(found);
}

// 非法 pretty 选项值触发解析错误并返回 false。
TEST(SinkStdoutTest, InvalidPrettyOption)
{
    std::vector<ConfigError> errors;
    PluginOptions opts{{"pretty", "maybe"}};
    auto [ok, out] = write_sink_and_capture(make_simple_root(), opts, errors);
    ASSERT_FALSE(ok);
    ASSERT_TRUE(out.empty());
    bool found = false;
    for (const auto & e : errors)
        if (e.message.find("invalid boolean for option 'pretty'") != std::string::npos)
        {
            found = true;
            break;
        }
    EXPECT_TRUE(found);
}